/*
 * Copyright (C) 2017-2019 Alibaba Group Holding Limited
 */

/******************************************************************************
 * @file     on2_vpu.c
 * @brief    CSI Source File for VPU Driver
 * @version  V1.4
 * @date     26. May 2019
 ******************************************************************************/

#include <stdio.h>
#include <string.h>

//#define VPU_PERF_TRACE
/* LOG_LEVEL: 0: Err; 1: Err&Warn; 2: Err&Warn&Info; 3: Err&Warn&Info&Debug */
#define LOG_LEVEL 0
#include <syslog.h>

#include <soc.h>
#include <drv_irq.h>
#include <drv_vpu.h>
#include <vpu_internal.h>

#include <ewl.h>
#include <enccommon.h>
#include <ewl_tx216_mm.h>
#include "EncJpegCodeFrame.h"
#include <aos/kernel.h>

#include "vpu_to_jpeg.h"

static JpegEncCfg	cfg;
static JpegEncIn	encIn;
static JpegEncOut	encOut;
static vpu_handle_t handle_dev;

extern void jpegSetNewFrame(jpegInstance_s *inst);
extern JpegEncRet JpegEncEncodeCfg(JpegEncInst inst, const JpegEncIn *pEncIn,JpegEncOut *pEncOut);
extern JpegEncRet JpegEncEncodeStart(JpegEncInst inst, const JpegEncIn *pEncIn, JpegEncOut *pEncOut);

#define VpuVirSize 20*1024    //virtual_size_20K
static char	VpuVirBuf[VpuVirSize] = {0};		 //virtual_buf_alloc_20k 
#define VpuOutBufSize 80*1024    //outbuf_alloc_80K
#define OutBufNum    2    //outbuf_num
#define ImageWidth    480
#define ImageHeight    640

static  u8 **pJpgBuffer_vpu = NULL;

int mjpeg_out_buffer_malloc()
{
   if(NULL == pJpgBuffer_vpu){
    pJpgBuffer_vpu = (u8 **)malloc(OutBufNum);
   	}
    if(NULL == pJpgBuffer_vpu){
		printf("pJpgBuffer_vpu malloc error !!!\r\n");	
		return -1;
    }
   memset(pJpgBuffer_vpu, 0, sizeof(OutBufNum));
   printf("pJpgBuffer_vpu =%p\n", pJpgBuffer_vpu);	

	if(NULL == (*pJpgBuffer_vpu)){
	    *pJpgBuffer_vpu = (u8 *)malloc(VpuOutBufSize);
	}else{
		printf("pJpgBuffer[0]_addr_err\n");
		return -1;
	}

    if ( NULL == pJpgBuffer_vpu[0]) {
        printf("pJpegBuffer[0]_malloc_fail\n");
        return -1;
    }
	memset(pJpgBuffer_vpu[0], 0, sizeof(VpuOutBufSize));

    printf("pJpgBuffer[0] =%p\n", pJpgBuffer_vpu[0]);
	if(NULL == pJpgBuffer_vpu[1]){
	    *(pJpgBuffer_vpu + 1) = (u8 *)malloc(VpuOutBufSize);
	}else{
		printf("pJpgBuffer[1]_addr_err\n");
		return -1;
	}
    if ( NULL == pJpgBuffer_vpu[1]) {
        printf("pJpegBuffer[1]_malloc_fail\n");
        return -1;
    }
	memset(pJpgBuffer_vpu[1], 0, sizeof(VpuOutBufSize));
    printf("pJpgBuffer[1] =%p\n", pJpgBuffer_vpu[1]);
    return 0;
}

int mjpeg_out_buffer_free()
{
    if (NULL != pJpgBuffer_vpu[0]) {
        free(pJpgBuffer_vpu[0]);
    }

    if (NULL != pJpgBuffer_vpu[1]) {
        free(pJpgBuffer_vpu[1]);
    }

    if (NULL != pJpgBuffer_vpu) {
        free(pJpgBuffer_vpu);
    }

    return 0;
}

JpegEncRet  vpu_test_jpeg_init(u8 *imageDataSource,u8 **pJpegBuffer, int imageWidth,int imageHeight)
{
	JpegEncRet  ret;
	u32  outbuf_size		   = VpuOutBufSize;    //imageWidth * imageHeight;
	u32  pict_bus_address    = (u32)imageDataSource; 
	u32 *outbuf_virt_address = (u32 *)VpuVirBuf;   //(u8 *)malloc(outbuf_size) ;

	if( NULL== (*pJpegBuffer)){
	  printf("pJpegBuffer_amlloc_is_=%p\r\n",*pJpegBuffer);
	}


	cfg.qLevel	 = 5;
#if 0 //JPEGENC_INPUT_YUV_FORMAT
  #if JPEG_YUV422_FORMAT
	  cfg.frameType  = JPEGENC_YUV422_INTERLEAVED_YUYV;
  #else
	  cfg.frameType  = JPEGENC_YUV420_PLANAR;  //input_format
  #endif
#else 
  #if JPEG_RGB565_FORMAT
	  cfg.frameType  = JPEGENC_RGB565; 
  #else
	  cfg.frameType  = JPEGENC_RGB888; 
  #endif
#endif
	cfg.codingType = JPEGENC_WHOLE_FRAME;
	cfg.unitsType  = JPEGENC_DOTS_PER_INCH;
	cfg.markerType = JPEGENC_SINGLE_MARKER;
	cfg.xDensity	 = 72;
	cfg.yDensity	 = 72;
	cfg.comLength  = 0;
	cfg.pCom		 = NULL;

	/* Step 2: Configuration of picture size */
	cfg.inputWidth   = imageWidth ;
	cfg.codingWidth  = imageHeight ;
	cfg.inputHeight  = imageHeight;
	cfg.codingHeight = imageWidth;



	cfg.xOffset	   = 0;
	cfg.yOffset	   = 0;
	cfg.rotation	   = JPEGENC_ROTATE_0;
	/* Restart interval 5 MCU rows (= 80 pixel rows), average quantization, encode whole frame at once */
	cfg.restartInterval = 5;

	encIn.pOutBuf    =(u8 *)outbuf_virt_address;
	encIn.busOutBuf  = (u32)(*pJpegBuffer );  //(outbuf_address);  
	encIn.outBufSize = outbuf_size; /* bytes */
	int_input_address = (u32 *)encIn.pOutBuf ;
	int_out_address=(u32 *)encIn.busOutBuf;
	//printf("out_address-busOutBuf = %p,input_address--pOutBuf = %p\n",int_out_address,int_input_address);

	encIn.frameHeader = 1;
	switch(cfg.frameType)
	{
	case JPEGENC_YUV422_INTERLEAVED_YUYV:
	  encIn.busLum = pict_bus_address;
	  break;
	case JPEGENC_YUV420_PLANAR:
	  encIn.busLum = pict_bus_address;
	  encIn.busCb  = encIn.busLum + cfg.inputWidth * cfg.inputHeight;
	  encIn.busCr  = encIn.busCb +	(cfg.inputWidth / 2) * (cfg.inputHeight / 2);
	  break;
	case JPEGENC_RGB565:
	  encIn.busLum = pict_bus_address;
	  break;
	case JPEGENC_RGB888:
	  encIn.busLum = pict_bus_address;
	  break;  
	default:
	  printf("input_image_format  error_no=%d\n",cfg.frameType);
	  return -1;
	}

	if ((ret = JpegEncInit(&cfg, &encoder)) != JPEGENC_OK) {
	/* Handle here the error situation */
		printf("JpegEncInit() failed. error_no=%d\n", ret);
	    return -1;
	}


	if ((ret = JpegEncSetPictureSize(encoder, &cfg)) != JPEGENC_OK) {
	   /* Handle here the error situation */
		printf("JpegEncSetPictureSize() failed. error_no=%d\n", ret);
	    return -1;
	}
    return JPEGENC_OK;
}



JpegEncRet  vpu_test_jpeg_start(u32 *OutSize)
{
	JpegEncRet  ret;
	//printf("VPU_ENCODE_BEGIN\r\n");

	ret =JpegEncEncodeCfg(encoder, &encIn, &encOut);
	if (ret  != JPEGENC_OK) {
		printf("JpegEncEncodeCfg() failed. error_no=%d\n", ret);
		return ret;
	}
	ret = JpegEncEncodeStart(encoder, &encIn, &encOut);  
	if (ret  != JPEGENC_OK) {
		printf("JpegEncEncodeStart() failed. error_no=%d\n", ret);
		return ret;
	}
   jpg_out_addr = (char *)encIn.busOutBuf;
   *OutSize = (u32)g_jpeg_Size;
  // g_InOdd ^= 1;

   //printf("VPU_ENCODE_END\r\n");
    //memcpy(jpg_out_addr,(u8 *)encIn.busOutBuf,g_jpeg_Size);
   //printf("jpg_out_addr =%p,busOutBuf = %p,g_jpeg_Size=%d\n", (u8 *)jpg_out_addr,encIn.busOutBuf,g_jpeg_Size);
//	encIn.busOutBuf = g_InOdd ? pJpgBuffer_vpu[1]:pJpgBuffer_vpu[0];




	return ret;

}



JpegEncRet  vpu_test_jpeg_end(void)
{
	JpegEncRet  ret;

	if ((ret = JpegEncRelease(encoder)) != JPEGENC_OK) {
		printf("JpegEncRelease() failed. error_no=%d\n", ret);
		return ret;
	}
	return ret;

}

/*******************************************************************************
Function:     fs_vpu_function
Description:  Simple jpg compression test API
Others:       just focus on the while
*******************************************************************************/
void vpu_function_init()
{
    JpegEncRet  ret;
    // u32 *OutJpegSize;
    // u32 length;
    drv_vpu_clk_enable(ENABLE);

    handle_dev = csi_vpu_initialize(0, NULL, NULL);

    if (NULL == handle_dev) {
        printf("csi_vpu_initialize() failed. \n");
        goto err_hander;
    }

	;
    if (mjpeg_out_buffer_malloc() == -1) 
	{  
        printf("mjpeg_out_buffer_malloc malloc error !!!\r\n");
        return;
    }

    if ((ret = vpu_test_jpeg_init((u8 *)VPU_OUT_UVC_BASE,pJpgBuffer_vpu,ImageWidth,ImageHeight)) != JPEGENC_OK)
	{ 
        printf("vpu_test_jpeg_init() failed. error_no=%d\n", ret);
         goto err_hander;
    }

    return;

err_hander:
    csi_vpu_uninitialize(handle_dev);
    return;
}

/*******************************************************************************
Function:     fs_vpu_function
Description:  Simple jpg compression test API
Others:       just focus on the while
*******************************************************************************/
void vpu_function_test()
{
    JpegEncRet  ret;
    u32 OutJpegSize;

	int_input_address=(u32 *)encIn.pOutBuf ;
	int_out_address=(u32 *)encIn.busOutBuf;
	if ((ret = vpu_test_jpeg_start(&OutJpegSize)) != JPEGENC_OK) {
	     printf("vpu_test_jpeg_start() failed. error_no=%d\n", ret);
	    // goto err_hander;
	}
 
    return;
// err_hander:
// 		csi_vpu_uninitialize(handle_dev);
// 		vpu_test_jpeg_end();
}

int jpeg_vpu_compress(u8 *ImageDataSource,u32 ImageLength,u8 *OutDataSource,u32 *OutLength)
{
	JpegEncRet  ret;
	u32 OutJpegSize;
	switch(cfg.frameType)
	{
		case JPEGENC_YUV422_INTERLEAVED_YUYV:
		  encIn.busLum = (u32)ImageDataSource;
		  break;
		case JPEGENC_YUV420_PLANAR:
		  encIn.busLum = (u32)ImageDataSource;
		  encIn.busCb  = encIn.busLum + ImageWidth * ImageHeight;
		  encIn.busCr  = encIn.busCb +	(ImageWidth / 2) * (ImageHeight/ 2);
		  break;
		case JPEGENC_RGB565:
		  encIn.busLum = (u32)ImageDataSource;
		  break;
		case JPEGENC_RGB888:
		  encIn.busLum = (u32)ImageDataSource;
		  break;  
		default:
		  printf("input_image_format  error_no=%d\n",cfg.frameType);
		  return -1;
	}
	encIn.busOutBuf = (u32)OutDataSource;
	int_input_address=(u32 *)encIn.pOutBuf ;
	int_out_address=(u32 *)encIn.busOutBuf;
	if ((ret = vpu_test_jpeg_start(&OutJpegSize)) != JPEGENC_OK) {
		 printf("vpu_test_jpeg_start() failed. error_no=%d\n", ret);
		// goto err_hander;
	}
	//memcpy(OutDataSource,encIn.busOutBuf,*OutJpegSize);
	//
	 *OutLength = OutJpegSize;
	return 0;

}




